require './Bond'
require './Atom'
require './AtomsChain'

class Molecule

  def initialize(smilesFormat)
    @atomsArray = Array.new;
    smilesString = smilesFormat.gsub(/\s+/, "").upcase 
    #validation
    if smilesString.gsub(/[C()]+/, "").length != 0 then
      raise "BAD SMILES FORMAT STRING !!! : " + smilesFormat;
    end
    buildFromSmilesFormatString(smilesString);
  end

  def getAllChains()
    chains = Array.new
    getLeaves().each do |leaf|
      traverseAndAddChains(AtomsChain.new, leaf, chains);
    end
    return chains;
  end
  
  private

  def buildFromSmilesFormatString(smilesFormat)
    currentPosition = smilesFormat.length - 1;
    atom = nil;
    while currentPosition >= 0
      if atom.nil? or smilesFormat[currentPosition] == ')' then
        if smilesFormat[currentPosition] == ')' then
          adjacentAtoms = Array.new
          unless atom.nil?
            adjacentAtoms.push(atom)
          end
          startOfParenthesis = findStartOfParenthesis(smilesFormat, currentPosition)
          subexpression = smilesFormat[startOfParenthesis + 1 .. currentPosition-1]
          headAtom = buildFromSmilesFormatString(subexpression)
          adjacentAtoms.push(headAtom)
          currentPosition = startOfParenthesis - 1
          if smilesFormat[currentPosition] == ')' then
            startOfParenthesis = findStartOfParenthesis(smilesFormat, currentPosition)
            subexpression = smilesFormat[startOfParenthesis + 1..currentPosition-1]
            headCarbon = buildFromSmilesFormatString(subexpression)
            adjacentAtoms.push(headCarbon)
            currentPosition = startOfParenthesis - 1
          end
          atom = Atom.new(adjacentAtoms)
        else
          atom = Atom.new
        end
      else
        adjacentAtoms = Array.new
        adjacentAtoms.push(atom);
        atom = Atom.new(adjacentAtoms);
      end
      currentPosition = currentPosition - 1;
      @atomsArray.push(atom);
    end
    return atom;
  end
  
  def findStartOfParenthesis(smilesString,endOfParenthesisPosition )
		nestingCounter = 0
		j = endOfParenthesisPosition
		while j >= 0
      case smilesString[j]
        when ')'
          nestingCounter = nestingCounter + 1
        when '('
          nestingCounter = nestingCounter - 1
      end
      if nestingCounter == 0 then
				return j
			end
		  j = j - 1
	  end
		raise "BAD FORMAT - Unmatched brackets: '" + smilesString + "':" + endOfParenthesisPosition.to_s
  end

  def getLeaves() 
    atoms = Array.new
    @atomsArray.each do |carbon|
      if carbon.getAdjacentAtoms.length < 2 then
        atoms.push(carbon);
      end
    end
    return atoms;
  end
  
  def traverseAndAddChains(currentChain,currentAtom,chains)
    bondsToNewAtoms = Array.new(currentAtom.bonds)
    if currentChain.atoms.length > 0 then
      lastAtom = currentChain.getLastAtom();
      currentAtom.getBonds().each do |bond|
        if (bond.getAtomAtOtherEndOfBond(currentAtom) == lastAtom)
          bondsToNewAtoms.delete(bond);
        end
      end
    end
    currentChain.addAtom(currentAtom);
    if bondsToNewAtoms.length == 0 then
      chains.push(currentChain);
    else
      bondsToNewAtoms.each do |bond|
        traverseAndAddChains(currentChain.copy(), bond.getAtomAtOtherEndOfBond(currentChain.getLastAtom()), chains);
      end
    end
  end

end